﻿using Exiled.API.Features;
using Exiled.Events.EventArgs.Player;
using Org.BouncyCastle.Utilities.Encoders;
using RgCore.API;
using RgCore.Database;
using RgCore.Misc;
using RgCore.PlayerHud;
using System;
using System.Collections.Generic;
using System.IO;
using UnityEngine;

namespace RgCore.GameData
{
    public struct Badge
    {
        public string Name;
        public string Color;
    }

    public class GameplayData
    {
        public GameplayData(Player player)
        {
            Player = player;
        }

        public Player Player { get; }
        public bool Initialized = false;
        public DateTime LastUpdates = DateTime.Now;

        public static string[] Hitokoto;

        public static List<GameplayData> GameDatas = new List<GameplayData>();

        /// <summary>
        /// 涉及到玩家初始化数据的事件。小提示：涉及I/O操作不需要异步
        /// </summary>
        public static event Action<Player> OnInitializingData;

        public static event Action<Player> OnInitializedData;

        public static event Action<Player> OnUploadingData;

        public static string GetLevelText(int transmigration, int level, bool colored)
        {
            string[,] texts = new string[,]
            {
                {"新进萌新", "见习玩家", "初出茅庐", "游刃有余", "出神入化", "炉火纯青", "一代宗师", "超凡脱俗", "登峰造极", "绝世枭雄" },
                {"渐入佳境", "得心应手", "驾轻就熟", "出类拔萃", "超群绝伦", "所向披靡", "中流砥柱", "百折不挠", "出神入化", "一念神魔" },
                {"才高八斗", "势如破竹", "光风霁月", "横扫千军", "风卷残云", "钟灵毓秀", "凤鸣九霄", "君临天下", "铸山煮海", "龙吟九霄" }
            };
            string name;
            string icon = string.Empty;
            string hex1 = string.Empty;
            string hex2 = string.Empty;
            if (level == 0)
            {
                hex1 = "#888888";
                icon = "✘";
                name = "禁用档案";
            }
            else if (transmigration <= 2)
            {
                int index;
                if (level < 10) index = 0;
                else if (level < 20) index = 1;
                else if (level < 30) index = 2;
                else if (level < 40) index = 3;
                else if (level < 50) index = 4;
                else if (level < 60) index = 5;
                else if (level < 70) index = 6;
                else if (level < 80) index = 7;
                else if (level < 90) index = 8;
                else index = 9;
                name = texts[transmigration, index];
                switch(transmigration)
                {
                    case 0:
                        hex1 = "#00FFFF";
                        icon = "♢";
                        break;
                    case 1:
                        hex1 = "#FFC125";
                        hex2 = "#00FA9A";
                        icon = "☆";
                        break;
                    case 2:
                        hex1 = "#9932CC";
                        hex2 = "#00BFFF";
                        icon = "⚝";
                        break;
                }
            }
            else
            {
                hex1 = "#8B0000";
                hex2 = "#FF8C69";
                string[] icons = { "★", "Ⅳ", "Ⅴ", "Ⅵ", "Ⅶ", "Ⅷ", "Ⅸ", "Ⅹ", "Ⅺ", "Ⅻ" };
                if (transmigration <= 12)
                    icon = icons[transmigration - 3];
                else
                    icon = transmigration.ToString();
                name = "天下无双";
            }
            if (!colored)
                return $"[Lv{level} {icon} {name}]";
            else if (hex2 == string.Empty)
                return $"<color={hex1}>[Lv{level} {icon} {name}]</color>";
            else
            {
                byte r1 = byte.Parse(hex1.Substring(1, 2), System.Globalization.NumberStyles.HexNumber);
                byte g1 = byte.Parse(hex1.Substring(3, 2), System.Globalization.NumberStyles.HexNumber);
                byte b1 = byte.Parse(hex1.Substring(5, 2), System.Globalization.NumberStyles.HexNumber);
                byte r2 = byte.Parse(hex2.Substring(1, 2), System.Globalization.NumberStyles.HexNumber);
                byte g2 = byte.Parse(hex2.Substring(3, 2), System.Globalization.NumberStyles.HexNumber);
                byte b2 = byte.Parse(hex2.Substring(5, 2), System.Globalization.NumberStyles.HexNumber);
                return API.API.GetGradientString($"[Lv{level} {icon} {name}]", new Color32(r1, g1, b1, 255), new Color32(r2, g2, b2, 255));
            }
        }

        public static void SetEnabled()
        {
            Exiled.Events.Handlers.Player.Verified.Subscribe(delegate (VerifiedEventArgs ev)
            {
                var data = new GameplayData(ev.Player);
                GameDatas.Add(data);
                data.InitializeDataAsync();
            });
            Exiled.Events.Handlers.Player.Destroying.Subscribe(delegate (DestroyingEventArgs ev)
            {
                var gd = GameDatas.Find(x => x.Player == ev.Player);
                if (gd == null)
                    return;
                gd.UploadAsync(true);
                GameDatas.Remove(gd);
            });
            string path = Path.Combine(Paths.Exiled, "sentences.txt");
            if (File.Exists(path))
            {
                Hitokoto = File.ReadAllLines(path);
            }
            else
            {
                Hitokoto = new string[] { "没有查到一言哦 =^=" };
            }
        }

        public async void InitializeDataAsync()
        {
            try
            {
                if (!DatabaseController.DatabaseDisabled)
                {
                    var filter = new Dictionary<string, object> { { "userid", Player.UserId } };
                    QueryCommandRequest data =
            new QueryCommandRequest(RgCore.instance.Config.Database.PlayerTable, filter, true,
            "transmigration", "level", "exp", "points", "mvp", "key_binded", "badge_preference",
            "scp_guarantees", "lastlogin", "qq")
            {
                Insert_Keys = filter
            };
                    List<Dictionary<string, object>> datas = await data.GetResponseResult();
                    if (datas == null)
                    {
                        Player.Kick("未能获取到你的游戏信息，这属于服务器的问题，请联系技术人员\n代码：EMPTY");
                        return;
                    }
                    Level = (int)datas[0]["level"];
                    Transmigration = (int)datas[0]["transmigration"];
                    Experience = (int)datas[0]["exp"];
                    Mvp = (int)datas[0]["mvp"];
                    Points = (int)datas[0]["points"];
                    BadgePreference = byte.Parse(datas[0]["badge_preference"].ToString());
                    KeyBinded = byte.Parse(datas[0]["key_binded"].ToString()) == 1;
                    NotScp_Con_Times = (int)datas[0]["scp_guarantees"];
                    LastLogin = DateTime.Parse(datas[0]["lastlogin"].ToString());
                    QQ = (string)datas[0]["qq"];
                }
                OnInitializingData?.Invoke(Player);
                Initialized = true;
                string sentence = API.API.GetHitokoto(true);
                string title = "超电磁炮服务器".GetGradientString(new Color32(14, 190, 255, 255), new Color32(255, 66, 179, 255));
                Player.SendRawMsg("welcome", $"<b><color=#FF6666>❀</color>  欢迎来到 {title} <color=#FF6666> ❀</color></b>" +
                    $"\n「{sentence}」", 10, ScreenLocation.CenterBottom, true);
                if (Player.DoNotTrack)
                {
                    Player.SendRawMsg("dnt", "<color=#B22222><b>[DO NOT TRACK]</b></color> <color=#EE5C42>你开启了DNT，根据VSR政策，你的游戏数据将不会被记录，如果你希望被记录：" +
                        "\n返回到主菜单，并在游戏设置-其它中关闭DNT</color>", 10, ScreenLocation.Top, true);
                }
                if (!DatabaseController.DatabaseDisabled)
                {
                    if (!KeyBinded)
                    {
                        Player.SendRawMsg("keybind", "<color=#B22222><b>[键位未绑定]</b></color> <color=#EE5C42>游玩本服务器需要绑定按键，否则你不会被匹配到任何插件类角色" +
                            "\n请按照群公告指示操作，并按下[B]键确认绑定成功</color>", 10, ScreenLocation.Top, true);
                    }
                    if (LastLogin.Date < DateTime.Now.Date)
                    {
                        AddExp(100, false);
                        AddPoints(5, false);
                        Player.SendFormattedMsg("", "<color=#7FFF00>每日登录</color>", "+100EXP +5积分 继续保持！", 3, MsgType.Notification, ScreenLocation.CenterTop, true);
                    }
                    NoResponseCommandRequest req = new NoResponseCommandRequest(RgCore.instance.Config.Database.PlayerTable,
    RequestType.Update,
    new Dictionary<string, object> { { "nickname", Player.Nickname }, { "lastlogin", DateTime.Now.Date.ToString("yyyy-MM-dd") }, { "online", true } },
    new Dictionary<string, object>() { { "userid", Player.UserId } });
                    await req.ProcessNonQuery();
                }
                else
                {
                    KeyBinded = true;
                    Player.SendRawMsg("dnt", "<color=#B22222><b>[数据库不可用]</b></color> <color=#EE5C42>当前服务器数据库不可用，你的数据不会被加载和保存" +
                       "\n请等待技术人员修复</color>", 10, ScreenLocation.Top, true);
                }
                OnInitializedData?.Invoke(Player);
            }
            catch (Exception ex)
            {
                Log.Error($"初始化玩家数据时出现错误：{ex}");
                Player.Kick("未能获取到你的游戏信息，这属于服务器的问题，请联系技术人员\n代码：EXCEPTION");
                return;
            }
        }

        public async void UploadAsync(bool offline = true)
        {
            if (!Initialized)
                return;
            if (!DatabaseController.DatabaseDisabled)
            {
                Dictionary<string, object> data_keys = new Dictionary<string, object>()
            {
                {"transmigration", _transmigration }, {"level", _level }, {"exp", _exp}, {"mvp", _mvp}, {"points", _points}, {"key_binded", KeyBinded},
                {"badge_preference", BadgePreference }, {"scp_guarantees", NotScp_Con_Times}, {"qq", QQ},
                {"lastlogin", DateTime.Now.Date.ToString("yyyy-MM-dd")}, {"online", !offline}
            };
                NoResponseCommandRequest data_req = new NoResponseCommandRequest(RgCore.instance.Config.Database.PlayerTable, RequestType.Update, data_keys, new Dictionary<string, object> { { "userid", Player.UserId } });
                await data_req.ProcessNonQuery();
            }
            if (offline)
            {
                OnUploadingData?.Invoke(Player);
            }
        }

        public void AddLevel(int amount, bool notification) => SetLevel(Level + amount, notification);

        public void SetLevel(int value, bool notification)
        {
            if (Player.DoNotTrack)
                return;
            if (Level == value)
                return;
            int origin = Level;
            int delta = value - origin;
            Level = value;
            if (notification)
            {
                string change = delta > 0 ? $"<color=#00FF00>(+{delta})</color>" : $"<color=#FF0000>({delta})</color>";
                Player.SendFormattedMsg("change", "<color=#00FFFF>数据变更</color>",
                    $"等级：<color=yellow>Lv{origin}</color> -> <color=yellow>Lv{value}</color> {change}", 5, MsgType.Notification, ScreenLocation.CenterTop, true);
            }
        }

        public void AddPoints(int amount, bool notification) => SetPoints(Points + amount, notification);

        public void SetPoints(int value, bool notification)
        {
            if (Player.DoNotTrack)
                return;
            if (Points == value)
                return;
            int origin = Points;
            int delta = value - origin;
            Points = value;
            if (notification)
            {
                string change = delta > 0 ? $"<color=#00FF00>(+{delta})</color>" : $"<color=#FF0000>({delta})</color>";
                Player.SendFormattedMsg("change", "<color=#00FFFF>数据变更</color>",
                    $"积分：<color=yellow>{origin}</color> -> <color=yellow>{value}</color> {change}", 5, MsgType.Notification, ScreenLocation.CenterTop, true);
            }
        }

        public void AddMvp(int amount, bool notification) => SetMvp(Mvp + amount, notification);

        public void SetMvp(int value, bool notification)
        {
            if (Player.DoNotTrack)
                return;
            if (Mvp == value)
                return;
            int origin = Mvp;
            int delta = value - origin;
            Mvp = value;
            if (notification)
            {
                string change = delta > 0 ? $"<color=#00FF00>(+{delta})</color>" : $"<color=#FF0000>({delta})</color>";
                Player.SendFormattedMsg("change", "<color=#00FFFF>数据变更</color>",
                    $"MVP次数：<color=yellow>{origin}</color> -> <color=yellow>{value}</color> {change}", 5, MsgType.Notification, ScreenLocation.CenterTop, true);
            }
        }

        public void AddExp(int amount, bool notification, bool slight = false)
        {
            if (Player.DoNotTrack)
                return;
            int value = Experience + amount;
            bool up = false;
            while (value >= MaxExperience)
            {
                value -= MaxExperience;
                _level++;
                up = true;
            }
            if (up)
            {
                Player.SendFormattedMsg("levelup", "<color=#FFB90F>等级提升</color>",
        $"恭喜你已升至 <color=#00FF00>{Level}</color> 级", 5, MsgType.Notification, ScreenLocation.CenterTop, true);
            }
            if (_level >= 100)
            {
                _transmigration++;
                _level -= 99;
                Player.SendRawMsg("change", new string[]
                {
                    "===================================",
                    $"<size=150%>----<<color=#00FF00><b>{_transmigration}</b></color>>----</size>",
                    "<size=100%><color=#FFD700>生涯满级</color></size>",
                    $"你已达到满级，等级将被重置并转生",
                    "==================================="
                }, 6, ScreenLocation.CenterTop, false);
            }
            SetExp(value, notification, slight);
        }

        public void SetExp(int value, bool notification, bool slight = false)
        {
            if (Player.DoNotTrack)
                return;
            if (slight)
            {
                if (_exp == value)
                    return;
                _exp = value;
            }
            else
            {
                if (Experience == value)
                    return;
                int origin = Experience;
                int delta = value - origin;
                Experience = value;
                if (notification)
                {
                    string change = delta > 0 ? $"<color=#00FF00>(+{delta})</color>" : $"<color=#FF0000>({delta})</color>";
                    Player.SendFormattedMsg("change", "<color=#00FFFF>数据变更</color>",
                        $"经验值：<color=yellow>{origin}</color> -> <color=yellow>{value}</color> {change}", 5, MsgType.Notification, ScreenLocation.CenterTop, true);
                }
            }
        }
        private int _transmigration = 0;
        private int _level = 1;
        private int _exp = 0;
        private int _mvp = 0;
        private int _points = 0;
        private bool _keybinded = false;
        private byte _badge_pref = 0;
        private int _unscp = 0;
        private string _qq;

        /// <summary>
        /// 玩家分数
        /// </summary>
        public int Score
        {
            get
            {
                if (ScoreMvpHandler.Scores.ContainsKey(Player.UserId))
                {
                    return ScoreMvpHandler.Scores[Player.UserId];
                }
                return 0;
            }
        }
        /// <summary>
        /// 转生次数
        /// </summary>
        public int Transmigration
        {
            get => Player.DoNotTrack ? 0 : _transmigration;
            private set
            {
                _transmigration = value;
            }
        }
        /// <summary>
        /// 玩家等级
        /// </summary>
        public int Level
        {
            get => Player.DoNotTrack ? 0 : _level;
            private set
            {
                _level = value;
            }
        }

        /// <summary>
        /// 玩家经验
        /// </summary>
        public int Experience
        {
            get => Player.DoNotTrack ? 0 : _exp;
            private set
            {
                _exp = value;
            }
        }

        public int MaxExperience => Transmigration > 0 ? 18000 :  Math.Min(18000, (_level * 150) + 850);

        /// <summary>
        /// 玩家MVP次数 ，修改后立即同步
        /// </summary>
        public int Mvp
        {
            get => Player.DoNotTrack ? 0 : _mvp;
            private set
            {
                _mvp = value;
            }
        }

        /// <summary>
        /// 玩家积分，修改后立即同步
        /// </summary>
        public int Points
        {
            get => Player.DoNotTrack ? 0 : _points;
            private set
            {
                _points = value;
                UploadAsync(false);
            }
        }

        /// <summary>
        /// 玩家是否拥有彩虹称号
        /// </summary>
        public bool RainbowBadge { get; set; }

        /// <summary>
        /// 玩家是否绑定键位
        /// </summary>
        public bool KeyBinded
        {
            get => _keybinded;
            set
            {
                _keybinded = value;
            }
        }

        /// <summary>
        /// 玩家称号偏好
        /// 0 - 没有 , 1 - 赞助, 2+  - 专属
        /// </summary>
        public byte BadgePreference
        {
            get => _badge_pref;
            set
            {
                _badge_pref = value;
            }
        }

        /// <summary>
        /// 玩家连续未成为SCP次数
        /// </summary>
        public int NotScp_Con_Times
        {
            get => Player.DoNotTrack ? 0 : _unscp;
            set
            {
                _unscp = value;
            }
        }

        /// <summary>
        /// 细节模式，HUD显示更多信息
        /// </summary>
        public bool DetailedMode { get; set; }

        public string QQ
        {
            get => _qq;
            set
            {
                _qq = value;
            }
        }

        public DateTime LastLogin { get; private set; }
        public Badge DonatorBadge { get; set; }
        public List<Badge> SpecialBadges { get; set; } = new List<Badge>();
    }
}